#include "FlashRuntimeExtensions.h"
#import "UIDeviceHardware.h"
#import <UIKit/UIKit.h>
#import <SystemConfiguration/SCNetworkReachability.h>
#import <CommonCrypto/CommonDigest.h>
#include <stdio.h>      
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/sockio.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <sys/sysctl.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>

void * tmpAddrPtr = NULL;
void * tmpbroadPtr = NULL;
char * iPVersion = "IPV4";
int PrefixLength = -1;
struct ifreq ifr;
BOOL getStatus(struct ifaddrs *ifa);
NSString* getConnectionType();
NSString* getMacAddress();
NSString* sha1(NSString* input);

FREObject GetInfos(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {
	
	FREObject retVal;
    
    NSString *model = [[UIDevice currentDevice] model];
    //Operating System Version
    NSString *systemVersion = [[UIDevice currentDevice] systemVersion];
    NSString *system = [[UIDevice currentDevice] systemName];
    
    //Deivce Version
    UIDeviceHardware *hwd=[[UIDeviceHardware alloc] init];
    NSString* deviceVersion = [hwd rawString];   
    [hwd release];
    
    // Get carrier name
    NSString *carrierName = @"";//Empty for simulator
    
    // Get mobile carrier code
    NSString *mcc = @"";//Empty for simulator
    NSString *mnc = @"";//Empty for simulator
    NSString* opCode = [mcc stringByAppendingString:mnc];
    
    
    // Country
    NSLocale* currentLocale = [NSLocale currentLocale]; 
    NSString* countryCode = [currentLocale objectForKey:@"kCFLocaleCountryCodeKey"];
    
    NSString* userId = sha1(getMacAddress());
    
	//User Agent
	UIWebView* webView = [[UIWebView alloc] init];
    NSString* userAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
    
    //JSON
    NSString* json = @"{";
    json = [json stringByAppendingFormat:@"\"ConnectionType\":\"%@\",",getConnectionType()];
    json = [json stringByAppendingFormat:@"\"Operator\":\"%@\",",opCode];
    json = [json stringByAppendingFormat:@"\"OperatorName\":\"%@\",",carrierName];
    json = [json stringByAppendingFormat:@"\"CountryISO\":\"%@\",",countryCode];
    json = [json stringByAppendingFormat:@"\"DeviceBrand\":\"%@\",",@"Apple"];
    json = [json stringByAppendingFormat:@"\"DeviceMake\":\"%@\",",@"Apple"];
    json = [json stringByAppendingFormat:@"\"DeviceModel\":\"%@\",",model];
    json = [json stringByAppendingFormat:@"\"Product\":\"\","];
    json = [json stringByAppendingFormat:@"\"UserAgent\":\"%@\",",userAgent];
    json = [json stringByAppendingFormat:@"\"OperatingSystem\":\"%@\",",system];
    json = [json stringByAppendingFormat:@"\"OperatingSystemVersion\":\"%@\",",systemVersion];
    json = [json stringByAppendingFormat:@"\"DeviceVersion\":\"%@\",",deviceVersion];
    json = [json stringByAppendingFormat:@"\"UserId\":\"%@\",",userId];
    json = [json stringByAppendingFormat:@"\"OperatorConnectionType\":\"\","];
    json = [json stringByAppendingFormat:@"\"SIM\":\"%@\",",opCode];
    json = [json stringByAppendingFormat:@"\"IsRoaming\":\"%d\"}",0];        
    
    
    const uint8_t *rawString=(const uint8_t *)[json cStringUsingEncoding:NSISOLatin1StringEncoding];
    FRENewObjectFromUTF8([json length], rawString, &retVal);
    
	return retVal;
}


void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet) {
    
	*numFunctionsToTest = 1;
	FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction));
    
	func[0].name = (const uint8_t*)"getInfos";
	func[0].functionData = NULL;
	func[0].function = &GetInfos;
	
	*functionsToSet = func;
}

void ContextFinalizer(FREContext ctx) {
	return;
}

void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet) {
	*extDataToSet = NULL;
	*ctxInitializerToSet = &ContextInitializer;
	*ctxFinalizerToSet = &ContextFinalizer;
}

void ExtFinalizer(void* extData) {
	return;
}


NSString* getConnectionType(){
    struct ifaddrs * ifAddrStruct = NULL;
	struct ifaddrs * ifa = NULL;
	char * InterfaceName = "";	
	getifaddrs(&ifAddrStruct);
    
	for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
        int cmp = strcmp(InterfaceName, (const char*)(ifa->ifa_name));	
        if (cmp != 0 ){  
            InterfaceName = ifa->ifa_name;
        } 
        if(getStatus(ifa)){
            if(strcmp(InterfaceName, "en0") == 0){
                return @"1";
            }
            
            NSString *string1 = [NSString stringWithCString:InterfaceName encoding:NSUTF8StringEncoding];
            if ([string1 rangeOfString:@"pdp"].location != NSNotFound) {
                return @"0";
            }
            break;
        }
    }
    return @"";
}

BOOL getStatus(struct ifaddrs *ifa)  { 
    
	BOOL state = false;
	
	if (ifa ->ifa_addr->sa_family == AF_INET){ 
		tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
		char addressBuffer[INET_ADDRSTRLEN];
		inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
		tmpbroadPtr = &((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr;
		struct sockaddr_in zeroAddress; 
		bzero(&zeroAddress, sizeof(zeroAddress)); 
		zeroAddress.sin_len = sizeof(zeroAddress); 
		zeroAddress.sin_family = AF_INET; 
		SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr*)&zeroAddress); 
		SCNetworkReachabilityFlags flags;
		BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
		CFRelease(defaultRouteReachability);
		
		if (!didRetrieveFlags){
			return FALSE;
		}
		
		BOOL isReachable = flags & kSCNetworkFlagsReachable;
		BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
		BOOL status = (isReachable && !needsConnection) ? YES : NO;
		
		
		if (status){ 
			if (strcmp(ifa->ifa_name, "en0") == 0 ){
				if (!(flags & kSCNetworkReachabilityFlagsIsWWAN)) {
					state= true;
				}else{
                    state= false;
			    }
            }else {   			  
				char *InterfaceStringPtr = ifa->ifa_name;
				NSString *string1 = [NSString stringWithCString:InterfaceStringPtr encoding:NSUTF8StringEncoding];
				if ([string1 rangeOfString:@"pdp"].location != NSNotFound) {
				    if ((flags & kSCNetworkReachabilityFlagsIsWWAN)){
					    state = true;
					}else{
					    state = false;
                    }
				}
		    }
		}
    }
    
    return state;
}

NSString* getMacAddress(){
    int                 mgmtInfoBase[6];
    char                *msgBuffer = NULL;
    size_t              length;
    unsigned char       macAddress[6];
    struct if_msghdr    *interfaceMsgStruct;
    struct sockaddr_dl  *socketStruct;
    NSString            *errorFlag = NULL;

    mgmtInfoBase[0] = CTL_NET;       
    mgmtInfoBase[1] = AF_ROUTE;     
    mgmtInfoBase[2] = 0;              
    mgmtInfoBase[3] = AF_LINK;       
    mgmtInfoBase[4] = NET_RT_IFLIST; 
    
    if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0){ 
        errorFlag = @"if_nametoindex failure";
    }else{
        if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0) {
            errorFlag = @"sysctl mgmtInfoBase failure";
        }else{
            if ((msgBuffer = malloc(length)) == NULL){
                errorFlag = @"buffer allocation failure";
            }else{
                if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
                    errorFlag = @"sysctl msgBuffer failure";
            }
        }
    }
    if (errorFlag != NULL){
        NSLog(@"Error: %@", errorFlag);
        return errorFlag;
    }
    interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
    socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
    memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
    NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                              macAddress[0], macAddress[1], macAddress[2], 
                              macAddress[3], macAddress[4], macAddress[5]];

    free(msgBuffer);
    return macAddressString;
}


NSString* sha1(NSString* input){
    const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:input.length];

    uint8_t digest[CC_SHA1_DIGEST_LENGTH];

    CC_SHA1(data.bytes, data.length, digest);

    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];

    return output;
}

